package com.ash.socketb.dual.end;

import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;

/**
 * 这个是一个双向通信的例子，典型的request-response机制
 * <p>
 * https://www.cnblogs.com/yiwangzhibujian/p/7107785.html#q1
 * <p>
 * 如何告知对方已发送完命令
 * 通过Socket关闭
 * 通过Socket关闭输出流的方式
 * 通过约定符号
 * 通过指定长度
 */
public class ClientDualDemo {

    public static void main(String[] args) throws IOException {


        System.out.println(sendReq("localhost", 8081, "asdfkasldf"));


    }

    /**
     * 注意事项
     * 这里有两个问题需要关注
     * \n 表示一个行结束，如果不加的，你用的是bufferedReader.readLine()就会一直阻塞，直到换行，手动写\n比较麻烦，你也可以通过PrintWriter 类封装流 通过pirntln方法进行写入请求/响应
     * end 表示业务结束标识，表示写入的内容结束，你可以 服务端或者客户端可以根据这个标识判断跳出循环，处理其他业务
     *
     * @param host
     * @param port
     * @param requestBody
     * @return
     * @throws IOException
     */
    private static String sendReq(String host, int port, String requestBody) throws IOException {
        try (
                Socket socket = new Socket(host, port);

                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()))
        ) {

            /**
             * 添加 \n 是为了确保结束标记 end 单独占据一行，这样在服务端接收数据时可以更容易地识别结束标记。
             *
             * 在这个示例中，当服务端使用 BufferedReader.readLine() 方法读取数据时，它会一直读取直到遇到换行符 \n 为止，因此在发送结束标记之前，先添加一个换行符可以确保结束标记独立成行，这样服务端就可以通过读取一行来判断是否收到结束标记。
             *
             * 如果不添加 \n，服务端可能会因为数据传输完成后不知道何时停止读取而导致阻塞或错误。
             */
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write((requestBody + "\n").getBytes(StandardCharsets.UTF_8));
            outputStream.write("end\n".getBytes(StandardCharsets.UTF_8));

            // 可以不调用这个 ，不然无法再次写入
            //socket.shutdownOutput();


            StringBuilder response = new StringBuilder();
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                if ("end".equals(line)) {
                    break;
                }
                response.append(line);
            }


            // 利用同一个socket再次请求

            outputStream.write((requestBody + "\n").getBytes(StandardCharsets.UTF_8));
            outputStream.write("end\n".getBytes(StandardCharsets.UTF_8));


            while ((line = bufferedReader.readLine()) != null) {
                if ("end".equals(line)) {
                    break;
                }
                response.append(line);
            }

            outputStream.write("close\n".getBytes(StandardCharsets.UTF_8));

            return response.toString();
        }
    }
}
